﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Configuration;
using System.Collections;
using System.Web;
using System.IO;
using System.Collections.Specialized;
using System.Xml;
using Utils;
namespace Utils.WebFramework
{
    public class Framework
    {
        private Framework() 
        {
            
        }

        public static Framework GetFramework() 
        {
            return framework;
        }

        public void Start() 
        {

        }

        public void Exit() 
        {
            controllerObjects.Clear();
            businessObjects.Clear();
            dataAccessObjects.Clear();

            controllers = null;
            dataAccess  = null;
            business = null;
        }

        public int SessionExpire 
        {
            get { return sessionExpire;  }
            set { sessionExpire = value; }
        }

        public string MainPath 
        {
            get { return mainPath;  }
            set { mainPath = value; }
        }

        public string ControllersPath
        {
            set 
            {
                SetConfigPath("controllers", value);
            }
        }

        public string BusinessPath
        {
            set
            {
                SetConfigPath("business", value);
            }
        }

        public string DataAccessPath
        {
            set 
            { 
                SetConfigPath("dataaccess", value);
            }
        }

        public string ResourcePath 
        {
            get { return resourcePath;  }
            set { resourcePath = value; }
        }

        public string ConnString 
        {
            get { return connString;  }
            set { connString = value; }
        }

        public string ViewsPath 
        {
            get { return viewsPath;  }
            set { viewsPath = value; }
        }

        public string IndexUrl
        {
            get { return indexUrl;  }
            set { indexUrl = value; }
        }

        public Encoding Encoding 
        {
            get { return encoding;  }
            set { encoding = value; }
        }

        public string Language 
        {
            get { return language;  }
            set { language = value; }
        }

        public Exception Error 
        {
            get { return ex;  }
            set { ex = value; }
        }

        public object GetController(string controllerName)
        {
            if (controllers == null)
            {
                controllers = Assembly.LoadFrom(mainPath + controllersFilePath);
            }

            object controllerObject = controllerObjects[controllerName];
            if (controllerObject == null)
            {
                controllerObject = controllers.CreateInstance(controllersNamespace + '.' + controllerName, true);
                controllerObjects[controllerName] = controllerObject;
            }

            ICacheObject cacheObject = controllerObject as ICacheObject;
            if (cacheObject != null)
            {
                cacheObject.Prepare();
            }


            return controllerObject;
        }

        public object GetBusiness(string businessName)
        {
            if (business == null)
            {
                business = Assembly.LoadFrom(mainPath + businessFilePath);
            }

            object businessObject = businessObjects[businessName];
            if (businessObject == null)
            {
                businessObject = business.CreateInstance(businessNamespace + '.' + businessName, true);
                businessObjects[businessName] = businessObject;
            }

            ICacheObject cacheObject = businessObject as ICacheObject;
            if (cacheObject != null)
            {
                cacheObject.Prepare();
            }

            return businessObject;
        }

        public object GetDataAccess(string dataAccessName)
        {
            if (dataAccess == null)
            {
                dataAccess = Assembly.LoadFrom(mainPath + dataAccessFilePath);
            }

            object dataAccessObject = dataAccessObjects[dataAccessName];
            if (dataAccessObject == null)
            {
                dataAccessObject = dataAccess.CreateInstance(dataAccessNamespace + '.' + dataAccessName, true);
                dataAccessObjects[dataAccessName] = dataAccessObject;
            }

            ICacheObject cacheObject = dataAccessObject as ICacheObject;
            if (cacheObject != null)
            {
                cacheObject.Prepare();
            }

            return dataAccessObject;
        }

        public void Refresh()
        {
            LoadResources();

            foreach (string dataAccessName in dataAccessObjects)
            {
                Object obj = dataAccessObjects[dataAccessName];

                ICacheObject cacheObject = obj as ICacheObject;
                if (cacheObject != null)
                {
                    cacheObject.Refresh();
                }
            }

            foreach (string businessName in businessObjects)
            {
                Object obj = businessObjects[businessName];

                ICacheObject cacheObject = obj as ICacheObject;
                if (cacheObject != null)
                {
                    cacheObject.Refresh();
                }
            }

            foreach (string controllerName in  controllerObjects)
            {
                Object obj = controllerObjects[controllerName];

                ICacheObject cacheObject = obj as ICacheObject;
                if (cacheObject != null)
                {
                    cacheObject.Refresh();
                }
            }
        }

        internal Resource GetResource(string langauge)
        {
            string supportLanguage = Resource.GetSupportLanguage(langauge.ToLower());

            if (resources == null)
            {
                resources = LoadResources();
            }

            Resource resource = (Resource)resources[supportLanguage];
            if (resource != null)
            {
                resource.originalLanguage = langauge;
            }

            return resource;
        }

        private Hashtable LoadResources() 
        {
            resources = new Hashtable();

            string[] fileNames = Directory.GetFiles(mainPath + resourcePath, "*.xml", SearchOption.AllDirectories);
            foreach (string fileName in fileNames)
            {
                Resource resource = LoadResource(fileName);
                if (resource != null)
                {
                    resources[resource.language] = resource;
                }
            }

            return resources;
        }

        private Resource LoadResource(string fileName)
        {
            XmlDocument doc = new XmlDocument();
            try
            {
                doc.Load(fileName);

                string language = string.Empty;
                XmlNode node = doc.SelectSingleNode("/resource/language");
                if ( node != null )
                {
                    language = node.InnerText.Trim();
                    if ( language != string.Empty )
                    {
                        Resource resource = new Resource();
                        resource.language = language.ToLower();

                        XmlNodeList itemNodes = doc.SelectNodes("/resource/items/item");
                        XmlAttribute attri = null;
                        foreach(XmlNode itemNode in itemNodes)
                        {
                            string name = string.Empty;

                            attri = itemNode.Attributes["name"];
                            if (attri != null) 
                            {
                                name = attri.Value.Trim();
                            }

                            if (name != string.Empty)
                            {
                                string eq = string.Empty;
                                attri = itemNode.Attributes["eq"];
                                if (attri != null)
                                {
                                    eq = attri.Value.Trim();
                                }

                                if (eq != string.Empty)
                                {
                                    resource[name] = resource[eq];
                                }
                                else 
                                {
                                    node = itemNode.SelectSingleNode("value");
                                    if (node != null)
                                    {
                                        resource[name] = node.InnerText.Trim();
                                    }
                                }
                            }
                        }

                        return resource;
                    }
                }
            }
            catch 
            {

            }

            return null;
        }

        private void SetConfigPath(string type, string path)
        {
            string[] items = path.Split(',');

            string filePath = items.Length > 0 ? items[0].Trim() : string.Empty;
            string namespc  = items.Length > 1 ? items[1].Trim() : string.Empty;
            if ( namespc == string.Empty && filePath != string.Empty)
            {
                int sPos = filePath.LastIndexOf('/');
                int ePos = filePath.LastIndexOf('.');

                if (sPos == -1)
                {
                    sPos = 0;
                }

                if (ePos == -1)
                {
                    ePos = filePath.Length;
                }

                if ( ePos > ++sPos )
                {
                    namespc = filePath.Substring(sPos, ePos - sPos);
                }
            }

            switch(type)
            {
                case "controllers": 
                {
                    controllersFilePath  = filePath;
                    controllersNamespace = namespc;
                }
                break;
                case "dataaccess":
                {
                    dataAccessFilePath  = filePath;
                    dataAccessNamespace = namespc;
                }
                break;
                case "business":
                {
                    businessFilePath  = filePath;
                    businessNamespace = namespc;
                }
                break;
                default:
                break;
            }
        }

        private static Framework framework = new Framework();

        private int sessionExpire = 480;

        private string mainPath = string.Empty;

        private string controllersFilePath  = string.Empty;
        private string controllersNamespace = string.Empty;

        private string businessFilePath     = string.Empty;
        private string businessNamespace    = string.Empty;

        private string dataAccessFilePath   = string.Empty;
        private string dataAccessNamespace  = string.Empty;

        private string resourcePath = string.Empty;

        private string connString = string.Empty;

        private string viewsPath = string.Empty;
        private string indexUrl  = string.Empty;

        private Encoding encoding = Encoding.UTF8;
        private string   language = string.Empty;

        private Assembly  controllers       = null;
        private Hashtable controllerObjects = new Hashtable();

        private Assembly  business = null;
        private Hashtable businessObjects = new Hashtable();

        private Assembly  dataAccess        = null;
        private Hashtable dataAccessObjects = new Hashtable();

        private Hashtable resources = null;

        private Exception ex = null;
    }
}
